﻿Imports System
Imports System.Collections
Imports System.Globalization
Imports System.Reflection
Imports System.Runtime.Serialization
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Compiler

Namespace System.Workflow.Activities
    Friend Class ParameterBindingValidator
        ' Methods
        Friend Shared Function Validate(ByVal manager As ValidationManager, ByVal obj As Object) As ValidationErrorCollection
            Dim validationErrors As New ValidationErrorCollection
            Dim activity As Activity = [TryCast](obj,Activity)
            If (Not TypeOf activity Is CallExternalMethodActivity AndAlso Not TypeOf activity Is HandleExternalEventActivity) Then
                Throw New ArgumentException(SR.GetString("Error_UnexpectedArgumentType", New Object() { GetType(Activity).FullName }), "obj")
            End If
            Dim type As Type = If(TypeOf activity Is CallExternalMethodActivity, DirectCast(activity, CallExternalMethodActivity).InterfaceType, DirectCast(activity, HandleExternalEventActivity).InterfaceType)
            If (Not type Is Nothing) Then
                Dim str As String = If(TypeOf activity Is CallExternalMethodActivity, DirectCast(activity, CallExternalMethodActivity).MethodName, DirectCast(activity, HandleExternalEventActivity).EventName)
                If String.IsNullOrEmpty(str) Then
                    Return validationErrors
                End If
                Dim parameterBindings As WorkflowParameterBindingCollection = If(TypeOf activity Is CallExternalMethodActivity, DirectCast(activity, CallExternalMethodActivity).ParameterBindings, DirectCast(activity, HandleExternalEventActivity).ParameterBindings)
                Dim method As MethodInfo = type.GetMethod(str)
                If ((method Is Nothing) AndAlso TypeOf activity Is CallExternalMethodActivity) Then
                    Return validationErrors
                End If
                Dim isEvent As Boolean = False
                If (method Is Nothing) Then
                    Dim eventInfo As EventInfo = type.GetEvent(str)
                    If ((eventInfo Is Nothing) OrElse (eventInfo.GetAddMethod(True) Is Nothing)) Then
                        Return validationErrors
                    End If
                    Dim eventHandlerType As Type = eventInfo.EventHandlerType
                    If (eventHandlerType Is Nothing) Then
                        eventHandlerType = TypeProvider.GetEventHandlerType(eventInfo)
                    End If
                    method = eventHandlerType.GetMethod("Invoke")
                    isEvent = True
                End If
                ParameterBindingValidator.ValidateParameterBinding(manager, activity, isEvent, str, method, parameterBindings, validationErrors)
            End If
            Return validationErrors
        End Function

        Private Shared Sub ValidateParameterBinding(ByVal manager As ValidationManager, ByVal activity As Activity, ByVal isEvent As Boolean, ByVal operation As String, ByVal mInfo As MethodInfo, ByVal parameterBindings As WorkflowParameterBindingCollection, ByVal validationErrors As ValidationErrorCollection)
            Dim hashtable As New Hashtable
            Dim parameters As ParameterInfo() = mInfo.GetParameters
            Dim flag As Boolean = False
            Dim info As ParameterInfo
            For Each info In parameters
                If TypeProvider.IsAssignable(GetType(ExternalDataEventArgs), info.ParameterType) Then
                    If (info.Position = 1) Then
                        flag = True
                    End If
                    ParameterBindingValidator.ValidateParameterSerializabiltiy(validationErrors, info.ParameterType)
                End If
                hashtable.Add(info.Name, info)
            Next
            If (isEvent AndAlso (Not flag OrElse (parameters.Length <> 2))) Then
                validationErrors.Add(New ValidationError(String.Format(CultureInfo.CurrentCulture, SR.GetString("Error_InvalidEventArgsSignature", New Object() { operation }), New Object(0  - 1) {}), &H120, False, "EventName"))
            End If
            If (Not mInfo.ReturnType Is GetType(Void)) Then
                hashtable.Add("(ReturnValue)", mInfo.ReturnParameter)
            End If
            Dim binding As WorkflowParameterBinding
            For Each binding In parameterBindings
                Dim parameterName As String = binding.ParameterName
                If Not hashtable.ContainsKey(parameterName) Then
                    If isEvent Then
                        validationErrors.Add(New ValidationError(String.Format(CultureInfo.CurrentCulture, SR.GetString("Error_InvalidEventPropertyName", New Object() { parameterName }), New Object(0  - 1) {}), &H120, False, "ParameterBindings"))
                    Else
                        validationErrors.Add(New ValidationError(String.Format(CultureInfo.CurrentCulture, SR.GetString("Error_InvalidMethodPropertyName", New Object() { parameterName }), New Object(0  - 1) {}), &H120, False, "ParameterBindings"))
                    End If
                    [Continue] For
                End If
                Dim obj2 As Object = Nothing
                If binding.IsBindingSet(WorkflowParameterBinding.ValueProperty) Then
                    obj2 = binding.GetBinding(WorkflowParameterBinding.ValueProperty)
                Else
                    obj2 = binding.GetValue(WorkflowParameterBinding.ValueProperty)
                End If
                If (Not obj2 Is Nothing) Then
                    Dim info2 As ParameterInfo = [TryCast](hashtable.Item(parameterName),ParameterInfo)
                    If (Not info2 Is Nothing) Then
                        Dim read As AccessTypes = AccessTypes.Read
                        If (info2.IsOut OrElse info2.IsRetval) Then
                            read = AccessTypes.Write
                        ElseIf info2.ParameterType.IsByRef Then
                            read = (read Or AccessTypes.Write)
                        End If
                        Dim errors As ValidationErrorCollection = ValidationHelpers.ValidateProperty(manager, activity, obj2, New PropertyValidationContext(binding, Nothing, parameterName), New BindValidationContext(If(info2.ParameterType.IsByRef, info2.ParameterType.GetElementType, info2.ParameterType), read))
                        validationErrors.AddRange(errors)
                    End If
                End If
            Next
        End Sub

        Private Shared Sub ValidateParameterSerializabiltiy(ByVal validationErrors As ValidationErrorCollection, ByVal type As Type)
            Dim customAttributes As Object() = type.GetCustomAttributes(GetType(SerializableAttribute), False)
            Dim type2 As Type = type.GetInterface(GetType(ISerializable).FullName)
            If ((customAttributes.Length = 0) AndAlso (type2 Is Nothing)) Then
                validationErrors.Add(New ValidationError(String.Format(CultureInfo.CurrentCulture, SR.GetString("Error_EventArgumentValidationException"), New Object() { type.FullName }), &H120, False, "EventName"))
            End If
        End Sub

    End Class
End Namespace

